package com.ambitious.controller;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ambitious.domain.*;
import com.ambitious.domain.academic.Academic;
import com.ambitious.domain.academic.BasicCourse;
import com.ambitious.domain.request_info.Status;
import com.ambitious.domain.token.EduToken;
import com.ambitious.domain.token.IndexToken;
import com.ambitious.service.EducationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;

/**
 * @author Ambitious
 */
@RestController
@CrossOrigin
@RequestMapping("/api")
@Slf4j
public class ApiController {

    private final Map<String, BasicCookieStore> cookieStoreMap;
    private final Map<String, CloseableHttpClient> clientMap;
    private final EducationService educationService;

    @Autowired
    public ApiController(Map<String, BasicCookieStore> cookieStoreMap ,Map<String, CloseableHttpClient> clientMap, EducationService educationService) {
        this.clientMap = clientMap;
        this.cookieStoreMap = cookieStoreMap;
        this.educationService = educationService;
    }

    /**
     * 获取数字广大首页，拿到jSessionId和lt，并保存lt
     * @return 存有数据的JSON
     */
    @GetMapping("/index")
    public IndexToken index() {
        IndexToken indexToken = new IndexToken();
        // 创建客户端对象
        BasicCookieStore cookieStore = new BasicCookieStore();
        CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
        String url = "https://newcas.gzhu.edu.cn/cas/login";
        HttpGet get = new HttpGet(url);
        // 发起请求，拿到响应回来的网页数据
        CloseableHttpResponse response = null;
        String value = null;
        cookieStore.clear();
        try {
            response = client.execute(get);
            value = EntityUtils.toString(response.getEntity());
        }catch (IOException ioe) {
            log.error("请求失败：{}", url);
        }
        // 获取JSESSIONID
        cookieStore.getCookies().forEach(v -> {
            if("JSESSIONID".equals(v.getName())) {
                indexToken.setJSessionId(v.getValue());
            }else if("SF_cookie_27".equals(v.getName())) {
                indexToken.setSfCookie27(v.getValue());
            }
        });
        if(value != null) {
            // 拿到校验码lt
            int ltIndex = value.indexOf("value=\"LT");
            String lt = value.substring(ltIndex).split("\"")[1];
            indexToken.setLt(lt);
            // 拿到校验码execution
            int exeIndex = value.indexOf("execution");
            String execution = value.substring(exeIndex+18,exeIndex+22);
            indexToken.setExecution(execution);
        }
        // 需要使用当前客户端继续操作不能关闭，需要将其存储到map中
        SecureRandomNumberGenerator generator = new SecureRandomNumberGenerator();
        String clientId = generator.nextBytes().toHex();
        clientMap.put(clientId,client);
        cookieStoreMap.put(clientId,cookieStore);
        indexToken.setClientId(clientId);
        return indexToken;
    }

    /**
     * 登录融合门户
     * @param student 登录时需要的验证数据
     * @return 用户登录融合门户的通行证
     */
    @PostMapping("/login")
    public String login(@RequestBody NewStudent student) throws IOException {
        log.info("收集的数据：{}",student);
        // 拿到当前用户的客户端
        CloseableHttpClient client = clientMap.get(student.getClientId());
        BasicCookieStore cookieStore = cookieStoreMap.get(student.getClientId());
        // 发送登录请求
        String url = "https://newcas.gzhu.edu.cn/cas/login";
        HttpPost post = new HttpPost(url);
        // 请求参数
        List<NameValuePair> urlParams = new ArrayList<>();
        urlParams.add(new BasicNameValuePair("ul",student.getUl()));
        urlParams.add(new BasicNameValuePair("pl",student.getPl()));
        urlParams.add(new BasicNameValuePair("rsa",student.getRsa()));
        urlParams.add(new BasicNameValuePair("execution",student.getExecution()));
        urlParams.add(new BasicNameValuePair("_eventId","submit"));
        urlParams.add(new BasicNameValuePair("lt",student.getLt()));
        post.setEntity(new UrlEncodedFormEntity(urlParams));
        post.setHeader("Cookie","JSESSIONID="+student.getJSessionId()+";SF_cookie_27="+student.getSfCookie27());
        // 发送请求，拿到结果
        cookieStore.clear();
        try {
            client.execute(post);
        } catch (IOException e) {
            log.error("请求失败：{}", url);
            return null;
        }
        // 获取进入教务系统的token
        String accessToken = "";
        for (Cookie cookie : cookieStore.getCookies()) {
            if("CASTGC".equals(cookie.getName())) {
                accessToken = cookie.getValue();
            }
        }
        if("".equals(accessToken)) {
            log.info("登录失败");
            return null;
        }
        log.info("CASTGC:{}",accessToken);
        // 拿到通行证之后即可关闭客户端
        clientMap.remove(student.getClientId());
        cookieStoreMap.remove(student.getClientId());
        client.close();
        return "{\"CASTGC\":\"" + accessToken + "\"}";
    }

    /**
     * 登录教务系统
     * @param CASTGC 融合门户通行证
     * @return 获取教务系统的token
     */
    @GetMapping("/education")
    public EduToken education(String CASTGC) throws IOException {
        EduToken eduToken = new EduToken();
        // 发送GET请求进入教务系统
        BasicCookieStore cookieStore = new BasicCookieStore();
        CloseableHttpClient client = HttpClients.custom().setDefaultCookieStore(cookieStore).build();
        cookieStore.clear();
        HttpGet get = new HttpGet("http://jwxt.gzhu.edu.cn/sso/driot4login");
        get.addHeader("Cookie","CASTGC=" + CASTGC);
        CloseableHttpResponse response = null;
        try {
            response = client.execute(get);
        } catch (IOException e) {
            eduToken.setStatus(Status.ERROR);
            eduToken.setMessage("请求教务系统数据失败");
            return eduToken;
        }
        if(response != null) {
            String value = EntityUtils.toString(response.getEntity());
            if(value.contains("修改密码")) {
                // 成功进入教务系统
                eduToken.setStatus(Status.SUCCESS);
                eduToken.setMessage("请求成功");
            }else {
                // 进入失败
                eduToken.setMessage("请求教务系统数据失败");
                eduToken.setStatus(Status.ERROR);
                return eduToken;
            }
        }
        // 获取教务系统token
        for (Cookie cookie : cookieStore.getCookies()) {
            if("JSESSIONID".equals(cookie.getName()) && eduToken.getJSessionId() == null) {
                eduToken.setJSessionId(cookie.getValue());
            }else if("SF_cookie_18".equals(cookie.getName())) {
                eduToken.setSfCookie18(cookie.getValue());
            }
        }
        return eduToken;
    }

    /**
     * 查询成绩
     * @param eduToken 教务系统token
     * @param year 学年
     * @param term 学期
     * @return 成绩列表
     */
    @GetMapping("/grade")
    public List<Grade> grade(EduToken eduToken, String year, String term) throws UnsupportedEncodingException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost("http://jwxt.gzhu.edu.cn/jwglxt/cjcx/cjcx_cxDgXscj.html?doType=query&su=");
        // 设置请求体参数
        List<NameValuePair> urlParams = new ArrayList<>();
        urlParams.add(new BasicNameValuePair("xnm",year));
        urlParams.add(new BasicNameValuePair("xqm",term));
        urlParams.add(new BasicNameValuePair("queryModel.showCount","100"));
        post.setEntity(new UrlEncodedFormEntity(urlParams));
        // 设置请求头参数
        post.setHeader("Cookie","JSESSIONID="+eduToken.getJSessionId()+"; SF_cookie_18="+eduToken.getSfCookie18());
        // 发送请求
        CloseableHttpResponse response3 = null;
        String value = null;
        try {
            response3 = client.execute(post);
            value = EntityUtils.toString(response3.getEntity());
        } catch (IOException e) {
            log.error("请求成绩数据失败");
        }
        List<Grade> gradeList = new ArrayList<>();
        log.info("value:{}",value);
        if(value != null && value.contains("items")) {
            // 将返回的结果封装为对象
            // 1 拿到items数组对应的字符串
            JSONObject jsonObject = JSONObject.parseObject(value);
            String grades = jsonObject.getString("items");
            // 2 去除字符串头尾两个中括号
            grades = grades.substring(1, grades.length() - 1);
            // 3 将字符串拆分
            String[] gradeListStr = grades.split("},\\{");
            for (String s : gradeListStr) {
                // 将大括号补充完整
                StringBuffer tmp = new StringBuffer();
                if(!s.startsWith("{")){
                    tmp.append('{');
                }
                tmp.append(s);
                if(!s.endsWith("}")){
                    tmp.append('}');
                }
                Grade grade = JSONObject.parseObject(tmp.toString(), Grade.class);
                gradeList.add(grade);
            }
        }else {
            // 查询不到结果，token失效
            return null;
        }
        return gradeList;
    }

    /**
     * 查询成绩
     * @param eduToken 教务系统token
     * @param year 学年
     * @param term 学期
     * @return 考试列表
     */
    @GetMapping("/exam")
    public List<Exam> exam(EduToken eduToken, String year, String term) throws UnsupportedEncodingException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost("http://jwxt.gzhu.edu.cn/jwglxt/kwgl/kscx_cxXsksxxIndex.html?doType=query&gnmkdm=N358105&su=");
        // 设置请求体参数
        List<NameValuePair> urlParams = new ArrayList<>();
        urlParams.add(new BasicNameValuePair("xnm",year));
        urlParams.add(new BasicNameValuePair("xqm",term));
        urlParams.add(new BasicNameValuePair("queryModel.showCount","100"));
        post.setEntity(new UrlEncodedFormEntity(urlParams));
        // 设置请求头参数
        post.setHeader("Cookie","JSESSIONID="+eduToken.getJSessionId()+"; SF_cookie_18="+eduToken.getSfCookie18());
        // 发送请求
        CloseableHttpResponse response3 = null;
        String value = null;
        try {
            response3 = client.execute(post);
            value = EntityUtils.toString(response3.getEntity());
        } catch (IOException e) {
            log.error("请求成绩数据失败");
        }
        List<Exam> examList = new ArrayList<>();
        log.info("value:{}",value);
        if(value != null && value.contains("items")) {
            // 将返回的结果封装为对象
            // 1 拿到items数组对应的字符串
            JSONObject jsonObject = JSONObject.parseObject(value);
            String grades = jsonObject.getString("items");
            // 2 去除字符串头尾两个中括号
            grades = grades.substring(1, grades.length() - 1);
            // 3 将字符串拆分
            String[] gradeListStr = grades.split("},\\{");
            for (String s : gradeListStr) {
                // 将大括号补充完整
                StringBuffer tmp = new StringBuffer();
                if(!s.startsWith("{")){
                    tmp.append('{');
                }
                tmp.append(s);
                if(!s.endsWith("}")){
                    tmp.append('}');
                }
                Exam exam = JSONObject.parseObject(tmp.toString(), Exam.class);
                examList.add(exam);
            }
        }else {
            return null;
        }
        return examList;
    }

    @GetMapping("/course")
    public CourseVO course(EduToken eduToken, String year, String term) throws UnsupportedEncodingException {
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost("http://jwxt.gzhu.edu.cn/jwglxt/kbcx/xskbcx_cxXsKb.html?gnmkdm=N2151&su=");
        // 拼接参数
        List<NameValuePair> params = new ArrayList<>();
        params.add(new BasicNameValuePair("xnm",year));
        params.add(new BasicNameValuePair("xqm",term));
        post.setEntity(new UrlEncodedFormEntity(params));
        post.setHeader("Cookie",String.format("JSESSIONID=%s;SF_cookie_18=%s",eduToken.getJSessionId(),eduToken.getSfCookie18()));
        CloseableHttpResponse response = null;
        String value = null;
        try {
            response = client.execute(post);
            value = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("value:{}", value);
        // 封装课表数据
        CourseVO courseVO = new CourseVO();
        if(value != null && value.contains("kbList")) {
            if(value.contains("kbList\":[]")) {
                // 查询不到成绩
                courseVO.setMessage("查无数据");
                courseVO.setStatus(Status.ERROR);
                return courseVO;
            }
            List<NormalCourse> normalCourseList = new ArrayList<>();
            // 将JSON字符串转成对象
            JSONObject jsonObject = JSONObject.parseObject(value);
            String kbList = jsonObject.getString("kbList");
            // 2 去除字符串头尾两个中括号
            kbList = kbList.substring(1, kbList.length() - 1);
            // 3 将字符串拆分
            String[] listStr = kbList.split("},\\{");
            // 计算总周数
            int totalWeek = -1;
            for (String s : listStr) {
                // 将大括号补充完整
                StringBuffer tmp = new StringBuffer();
                if(!s.startsWith("{")){
                    tmp.append('{');
                }
                tmp.append(s);
                if(!s.endsWith("}")){
                    tmp.append('}');
                }
                NormalCourse normalCourse = JSONObject.parseObject(tmp.toString(), NormalCourse.class);
                // 获取当前课程的最大周数
                String[] weeks = normalCourse.getZcd().split("-");
                StringBuilder maxWeek = new StringBuilder(weeks[weeks.length - 1]);
                int i = maxWeek.lastIndexOf(",");
                int j = maxWeek.lastIndexOf("周");
                int max = Integer.parseInt(maxWeek.substring(i + 1, j));
                if(max > totalWeek) {
                    totalWeek = max;
                }
                normalCourseList.add(normalCourse);
            }
            List<WeekCourse> weekCourses = educationService.getWeekCourses(normalCourseList, totalWeek);
            courseVO.setTotalWeek(totalWeek);
            courseVO.setWeeks(weekCourses);
            // 封装其他课程
            if(value.contains("sjkList")) {
                List<SpecialCourse> specialCourseList = new ArrayList<>();
                String sjkList = jsonObject.getString("sjkList");
                // 2 去除字符串头尾两个中括号
                sjkList = sjkList.substring(1, sjkList.length() - 1);
                // 3 将字符串拆分
                String[] listStr2 = sjkList.split("},\\{");
                for (String s : listStr2) {
                    // 将大括号补充完整
                    StringBuffer tmp = new StringBuffer();
                    if(!s.startsWith("{")){
                        tmp.append('{');
                    }
                    tmp.append(s);
                    if(s.endsWith("[]}")) {
                        tmp.append("}");
                    }else if(!s.endsWith("}")){
                        tmp.append('}');
                    }
                    SpecialCourse specialCourse = JSONObject.parseObject(tmp.toString(), SpecialCourse.class);
                    specialCourseList.add(specialCourse);
                }
                courseVO.setSpecialCourseList(specialCourseList);
            }
            courseVO.setMessage("查询成功");
            courseVO.setStatus(Status.SUCCESS);
            return courseVO;
        }else {
            courseVO.setMessage("请求失败");
            courseVO.setStatus(Status.ERROR);
            return courseVO;
        }
    }

    /**
     * 获取学业情况相关信息
     * @param eduToken 教务系统token
     * @return 学业信息
     */
    @GetMapping("/academic_info")
    public Academic academicInfo(EduToken eduToken) throws IOException {
        // 1 初始化对象
        Academic academic = new Academic();
        // 2 登录学业页面
        CloseableHttpClient client = HttpClients.createDefault();
        HttpGet get = new HttpGet("http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxXsxyqkIndex.html?gnmkdm=N105515");
        get.addHeader("Cookie",String.format("JSESSIONID=%s;SF_cookie_18=%s",eduToken.getJSessionId(),eduToken.getSfCookie18()));
        CloseableHttpResponse response = client.execute(get);
        String value = EntityUtils.toString(response.getEntity());
        if(value.contains("您的课程修读情况")) {
            // 处理每一个课程分类的最低学分limitCredit
            educationService.setLimitCredit(academic, value);
        }else {
            academic.setMessage("请求失败");
            academic.setStatus(Status.ERROR);
            return academic;
        }
        // 3 获取学科基础课程数据
        HttpPost post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "86DA0AE145485B1EE053206411ACB500");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        List<BasicCourse> courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getJc(), courses);
        // 4 获取专业必修课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "86DA0AE145495B1EE053206411ACB500");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getZybx(), courses);
        // 5 获取集中性实践教学环节数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "86DA0AE1454A5B1EE053206411ACB500");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getJzx(), courses);
        // 6 获取通识类必修课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "86DA0AE1454B5B1EE053206411ACB500");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getTsbx(), courses);
        // 6 教师教育类必修课程
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "86DA0AE1454C5B1EE053206411ACB500");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getJsjy(), courses);
        // 7 获取方向模块数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "d4420cd2e82d11eb950bedbd42ca052f");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getFxmk(), courses);
        // 8 获取专业选修课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "d4420cd3e82d11eb9615edbd42ca052f");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getZyxx(), courses);
        // 9 获取创新与创业课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqFKcxx.html", "20190630cxcy");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getCxcy(), courses);
        // 10 获取历史与文化课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqFKcxx.html", "20190630lswh");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getLswh(), courses);
        // 11 获取大学体育5,6数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "3f61f242babb11eaa65bcffd5fbc81fd");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getDxty(), courses);
        // 12 获取艺术与审美课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqFKcxx.html", "20190630yssm");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getYssm(), courses);
        // 13 获取精品思政课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "94722C74B62578F7E0530100007F009A");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getJpsz(), courses);
        // 14 获取其他课程数据
        post = educationService.initAcademicPost(eduToken, "http://jwxt.gzhu.edu.cn/jwglxt/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html", "qtkcxfyq");
        response = client.execute(post);
        value = EntityUtils.toString(response.getEntity());
        courses = JSONArray.parseArray(value, BasicCourse.class);
        educationService.setCourseInfo(academic.getQt(), courses);
        academic.setMessage("请求成功");
        academic.setStatus(Status.SUCCESS);
        return academic;
    }
}
